# -*- coding: utf-8 -*-
"""
Module Description: 活动邮件发件
Date: 2017/10/31
Author: FQ
"""
from collections import defaultdict

from pyshare.bll.lang.translate import translate_config_to_dict
from pyshare.dal.dal_adapters import character_adapters as cadts
from pyshare.dal.repository_impl import RoleRepository, AllianceBattleActivityRepository, \
    AllianceBattleLeaderAwardSignRepository, AllianceMemberRepository, MoonRoleRecordRepository, \
    QueenJewelryRoleRecordRepository, QueenJewelryActivityRepository, \
    BanquetActivityRepository, BanquetRoleRecordRepository
from pyshare.dal.repository_impl.ruins_repository import RuinsRoleRepository, RuinsActivityRepository
from pyshare.const.enums.activity import ActivityClass, ActivityType

from pyshare.dal.gameconfig.game_env import get_config_env_set, GameConfigEnvLang
from pyshare.utils.unique_key import create_idx
from pyshare.const.enums.reusable_activity import ReusableActivityRankType
from pyshare.const.enums.alliance_battle import AllianceSingleAwardType, AllianceBattleRankingKey
from pyshare.utils.time_utils import getCT, has_pass_time
from pyshare.redis_cache.area_cache_key_define import AllianceSiegeRank
from common.service_config import get_server_id, get_app_id
from pyshare.const.enums.ruins import RuinsRankType
from pyshare.dal.repository_impl import RankActivityRepository, ReusableActivityRepository, \
    RoleRankActivityRecordRepository, RankAllianceMemberRecordRepository, RoleReusableActivityRepository, \
    RankingAwardStatusRepository
from pyshare.dal.gameconfig.query import getProfile


class RankActivitySendAward(object):
    """
    普通榜单类活动，未领取邮件发奖类
    **增加新的类型活动发件，继承该类时注意以下几点
    1.确保活动记录/角色领取记录有统一的获取以及修改的方法
    2.如果获取排行数据不一样需要重新定义get_rank_data方法
    """

    def __init__(self, activity_id):
        self.activity_class = ActivityClass.Rank
        self.activity_id = activity_id  # 活动id
        self.activity = self.get_activity()  # 活动实例
        self.role_id_list = []  # 待发邮件的rid列表
        self.fail_sid_list = []  # 邮件失败rid列表
        # 邮件奖励Id字典 /联盟活动表示盟主邮件奖励字典(用于保存相同奖励的邮件奖励id，减少重复创建)
        self.award_id_dict = {}
        self.role_rank_dict = defaultdict(list)  # 数据字段{排名: record_list]}
        # 邮件标题(多语言)
        self.subject = getattr(GameConfigEnvLang(), 'ActivityMailSubject')
        # 邮件内容(多语言)
        self.content = getattr(GameConfigEnvLang(), 'RankActivityContent')

    ###############################################
    def get_activity(self):
        """
        返回活动适配器实例
        :return:
        """
        return RankActivityRepository.get_by_activityid(self.activity_id)

    def get_activity_range_cfg(self):
        """获取排名奖励区间配置"""
        return self.activity.range

    def get_activity_name(self):
        """获取活动名称(多语言)"""
        # 从TcActivityType表中获取活动名称
        env_key = getProfile('TcActivityType', Class=self.activity_class, Type=self.activity.type).LangEnvKey
        return getattr(GameConfigEnvLang(), env_key)

    def get_award_list_cfg(self):
        """获取活动奖励配置"""
        return self.activity.award_list

    ###############################################
    def rank_to_award_index(self, rank):
        """
        返回排名对应的奖励下标
        :param rank:
        :return:
        """
        for w_index, r in enumerate(self.get_activity_range_cfg()):
            if r[0] <= rank <= r[1]:
                return w_index
        return None

    def get_start_end(self):
        """
        返回发奖排名区间 Start, End
        :return:
        """
        range_cfg = self.get_activity_range_cfg()
        return range_cfg[0][0] - 1, range_cfg[-1][-1] - 1

    def get_subject(self):
        name_lang = self.get_activity_name()

        subject = {}
        for code, msg in self.subject.items():
            subject[code] = msg.format(name=name_lang[code])

        return subject

    def get_content(self, rank):
        """
        返回邮件内容(多语言)
        :param rank:
        :return:
        """
        content = {}
        name_lang = self.get_activity_name()

        for code, msg in self.content.items():
            content[code] = msg.format(name=name_lang[code], rank=rank)

        return content

    @staticmethod
    def get_role_service_id(role_id_list):
        """
        返回 role_id_list中 对应角色的 service_id
        :param role_id_list: role id 列表
        :return:
        """
        return {r.role_guid: r.service_id for r in
                RoleRepository.filter_by_rid_list(role_id_list,
                                                  'RoleGuid', 'ServiceId')}

    def get_rank_data(self):
        """
        返回 排名start至排名end之间的角色排名字典  {role_id: 排名}
        :return:
        """
        from app.area.core.component_center import ComponentCenter
        area_cc = ComponentCenter()
        start, end = self.get_start_end()
        rank_data = area_cc.activity.get_rank_activity_leader(self.activity, start=start, end=end)

        return {r[0]: index + 1 for index, r in enumerate(rank_data)}

    def get_not_award_record_list(self, *args):
        """TODO 子类需要重写该方法"""
        return RoleRankActivityRecordRepository.filter_by_not_award(self.role_id_list, self.activity_id)

    def init_rank_record_dict(self):
        """
        初始化 榜单上待发奖的角色数据
        role_id_list 需要发奖的角色id列表
        role_rank_dict 发奖方法中的发奖数据 {排名: [role_id,]}
        :return:
        """
        rank_dict = self.get_rank_data()
        self.role_id_list = rank_dict.keys()
        record_list = self.get_not_award_record_list()

        self.role_rank_dict = {rank_dict.get(r.role_guid): [r] for r in record_list}

    def get_rank_award_cfg(self, rank, is_award_list=True):
        """
        返回排名对应的奖励配置
        :param rank: 排名
        :param is_award_list:
        True则从Activity.AwardList中获取
        否则从Activity.AlliancePAwardList中获取
        :return:
        """
        award_index = self.rank_to_award_index(rank)
        if award_index not in self.award_id_dict:
            self.award_id_dict[award_index] = create_idx()

        return self.get_award_list_cfg()[award_index], award_index, self.award_id_dict[award_index]

    def set_record_has_award(self, rid_list):
        """TODO 设置记录为已领取"""
        RoleRankActivityRecordRepository.update_many_has_award(rid_list, self.activity_id)

    def response_callback(self, res, s_id_to_role_id_dict):
        """
        回调结果处理
        发送成功的邮件，将角色领奖记录置成1
        发送失败的邮件，将role_id 计入 fail_sid_list
        :param res:
        :param s_id_to_role_id_dict: {sid: rid}
        :return:
        """
        if res and 'Success' in res:
            rid_list = [s_id_to_role_id_dict.get(sid) for sid in res['Success']]
            self.set_record_has_award(rid_list)
            self.fail_sid_list += list(set(s_id_to_role_id_dict.keys()) - set(res['Success']))
        else:
            self.fail_sid_list += s_id_to_role_id_dict.keys()

    def send_single_person_award(self, service_id_dict, rank_dict, is_award_list=True):
        """
        发送奖励
        个人排行奖励
        :return:
        """
        from app.admin.core.admin_component_center import AdminComponentCenter
        admin_cc = AdminComponentCenter()

        for rank, record_list in rank_dict.iteritems():
            # 邮件奖励说明
            content = self.get_content(rank)
            subject = self.get_subject()

            award_list, index, award_id = self.get_rank_award_cfg(rank, is_award_list)
            s_id_to_role_id_dict = {service_id_dict.get(r.role_guid): r.role_guid for r in record_list}
            res_data = admin_cc.activity_admin.send_mail(award_list, s_id_to_role_id_dict.keys(), subject, content)
            self.response_callback(res_data, s_id_to_role_id_dict)

    def send_award(self):
        """
        执行发奖
        外部只需要调用该方法就可完成发奖
        :return:
        """
        self.init_rank_record_dict()
        service_id_dict = self.get_role_service_id(self.role_id_list)
        self.send_single_person_award(service_id_dict, self.role_rank_dict)
        return self.fail_sid_list


class MoonActivitySendAward(RankActivitySendAward):
    """博饼活动个人榜单邮件发奖"""

    def __init__(self, activity_id):
        super(MoonActivitySendAward, self).__init__(activity_id)

    def get_not_award_record_list(self, *args):
        """获取未领取奖励的记录"""
        return MoonRoleRecordRepository.filter_by_not_award(self.role_id_list, self.activity_id)

    def set_record_has_award(self, rid_list):
        """TODO 设置记录为已领取"""
        MoonRoleRecordRepository.update_many_has_award(rid_list, self.activity_id)


class AllianceActivitySendAward(RankActivitySendAward):
    """联盟活动榜单邮件发件"""

    def __init__(self, activity_id):
        super(AllianceActivitySendAward, self).__init__(activity_id)
        self.member_award_id_dict = {}  # 盟友奖励id字段(用于保存相同奖励的邮件奖励id，减少重复创建)
        self.alliance_p_id_list = []  # 盟友rid列表
        self.alliance_p_role_rank_dict = defaultdict(list)  # 盟友奖励数据字典{排名: record_list} 用于最后发奖
        self.content = getattr(GameConfigEnvLang(), 'AllianceRankActivityContent')

    def get_alliance_p_award_cfg(self):
        """返回盟友奖励配置"""
        return self.activity.alliance_p_award_list

    def get_not_award_record_list(self, *args):
        """获取未领取记录"""
        return RankAllianceMemberRecordRepository.filter_by_not_award(args[0], self.activity_id)

    def set_record_has_award(self, rid_list):
        """设置记录为已领取"""
        RankAllianceMemberRecordRepository.update_many_has_award(rid_list, self.activity_id)

    def init_rank_record_dict(self):
        """初始化榜单上的领取记录 - 字典"""
        rank_dict = self.get_rank_data()
        alliance_id_list = rank_dict.keys()
        record_list = self.get_not_award_record_list(alliance_id_list)

        for record in record_list:
            rank = rank_dict.get(record.alliance_id)
            if record.is_leader:
                self.role_id_list.append(record.role_guid)
                self.role_rank_dict[rank].append(record)
            else:
                self.alliance_p_id_list.append(record.role_guid)
                self.alliance_p_role_rank_dict[rank].append(record)

    def get_rank_award_cfg(self, rank, is_award_list=True):
        """获取奖励配置"""

        award_index = self.rank_to_award_index(rank)
        award_id_dict = self.award_id_dict if is_award_list else self.member_award_id_dict
        award_list = self.get_award_list_cfg() if is_award_list else self.get_alliance_p_award_cfg()

        if award_index not in award_id_dict:
            award_id_dict[award_index] = create_idx()

        return award_list[award_index], award_index, award_id_dict[award_index]

    def send_award(self):
        """
        执行发奖
        外部只需要调用该方法就可完成发奖
        :return:
        """
        # 初始化发奖数据
        self.init_rank_record_dict()
        # 发送盟主奖励
        leader_service_id_list = self.get_role_service_id(self.role_id_list)
        self.send_single_person_award(leader_service_id_list, self.role_rank_dict)

        # 发送盟友奖励
        service_id_list = self.get_role_service_id(self.alliance_p_id_list)
        self.send_single_person_award(service_id_list, self.alliance_p_role_rank_dict, is_award_list=False)
        return self.fail_sid_list


class ReusableActivitySendAward(object):
    """
    万能活动
    """

    def __init__(self, activity_id):
        self.activity_id = activity_id
        self.fail_sid_list = []

    class PersonAward(RankActivitySendAward):
        """
        万能活动个人榜单邮件发奖
        """

        ###############################################
        def get_activity(self):
            """获取活动"""
            return ReusableActivityRepository.get_by_activityid(self.activity_id)

        def get_activity_range_cfg(self):
            """获取排名奖励区间配置"""
            return self.activity.personal_range_list

        def get_activity_name(self):
            """获取活动名称"""
            cfg = getProfile('TcReusableActivityType', Type=self.activity.activity_type)
            return getattr(GameConfigEnvLang(), cfg.LangEnvKey)


        def get_award_list_cfg(self):
            """获取活动奖励配置"""
            return self.activity.personal_award_list

        ###############################################

        def get_rank_data(self):
            """
            返回 排名start至排名end之间的角色排名字典  {role_id: 排名}
            :return:
            """

            start, end = self.get_start_end()
            return ReusableActivitySendAward.reusable_rank_data(self.activity_id, ReusableActivityRankType.Personal,
                                                                start, end)

        def get_not_award_record_list(self, *args):
            return RoleReusableActivityRepository.filter_by_personal_not_award(self.role_id_list, self.activity_id)

        def set_record_has_award(self, rid_list):
            RoleReusableActivityRepository.update_many_personal_has_award(rid_list, self.activity_id)

    class AllianceAward(AllianceActivitySendAward):
        """联盟榜单邮件发奖"""

        ###############################################
        def get_activity(self):
            """获取活动"""
            return ReusableActivityRepository.get_by_activityid(self.activity_id)

        def get_activity_range_cfg(self):
            """获取排名奖励区间配置"""
            return self.activity.alliance_range_list

        def get_activity_name(self):
            """获取活动名称"""
            cfg = getProfile('TcReusableActivityType', Type=self.activity.activity_type)
            return getattr(GameConfigEnvLang(), cfg.LangEnvKey)

        def get_award_list_cfg(self):
            """获取盟主活动奖励配置"""
            return self.activity.alliance_leader_award_list

        def get_alliance_p_award_cfg(self):
            """返回盟友奖励配置"""
            return self.activity.alliance_member_award_list

        ###############################################

        def get_rank_data(self):
            """
            返回 排名start至排名end之间的角色排名字典  {role_id: 排名}
            :return:
            """
            start, end = self.get_start_end()
            return ReusableActivitySendAward.reusable_rank_data(self.activity_id, ReusableActivityRankType.Alliance,
                                                                start, end)

    @classmethod
    def reusable_rank_data(cls, activity_id, rank_type, start, end):
        from app.area.core.component_center import ComponentCenter
        area_cc = ComponentCenter()
        rank_redis_key = area_cc.reusable_activity.get_rank_redis_key(rank_type, activity_id)
        rank_data = area_cc.leaderboard.get_rank_list(rank_redis_key, start=start, end=end, need_id=True)
        return {r[0]: index + 1 for index, r in enumerate(rank_data)}

    def send_award(self):
        """
        执行发邮件
        外部只需要调用该方法就可完成发奖
        :return:
        """
        # 发送个人榜单
        personal = self.PersonAward(self.activity_id)
        fail_list = personal.send_award()
        self.fail_sid_list.append(fail_list)

        # 发送联盟榜单
        alliance = self.AllianceAward(self.activity_id)
        fail_list = alliance.send_award()
        self.fail_sid_list.append(fail_list)

        return self.fail_sid_list


####################################
# 盟战相关
####################################
class AllianceBattleScoreRankSendAward(AllianceActivitySendAward):
    """
    盟战积分榜单发奖
    """

    def __init__(self):
        super(AllianceBattleScoreRankSendAward, self).__init__(None)

    def get_activity(self):
        return None

    def get_activity_name(self):
        return getattr(GameConfigEnvLang(), 'AllianceBattleScoreMailName')

    def get_start_end(self):
        """
        返回发奖排名区间 Start, End
        :return:
        """
        from app.area.component.alliance_battle.alliance_battle_result_component import AllianceBattleResultComponent

        cfg = AllianceBattleResultComponent.get_score_rank_award_cfg_list(None)

        return cfg[0]['RankMin'], cfg[-1]['RankMax']

    def get_rank_award_cfg(self, rank, is_award_list=True):
        """
        返回排名对应的奖励配置
        :param rank: 排名
        :param is_award_list:
        True则从Activity.AwardList中获取
        否则从Activity.AlliancePAwardList中获取
        :return:
        """
        from app.area.component.alliance_battle.alliance_battle_result_component import AllianceBattleResultComponent

        award_cfg = AllianceBattleResultComponent.get_score_rank_award_cfg(None, rank)

        award_list = award_cfg['Award'] if is_award_list else award_cfg['LeaguerAward']
        award_index = award_cfg['Id']
        award_id_dict = self.award_id_dict if is_award_list else self.member_award_id_dict

        if award_index not in award_id_dict:
            award_id_dict[award_index] = create_idx()

        return award_list, award_index, award_id_dict[award_index]

    def get_rank_data(self):
        """
        返回 排名start至排名end之间的角色排名字典  {alliance_id: 排名}
        :return:
        """
        from pyshare.bll.utils.area.rank_utils import JoinRankManger
        start, end = self.get_start_end()
        ranking = JoinRankManger()
        rank_key = AllianceBattleRankingKey.NewAllianceBattleRankingKey.format(srv_id=get_server_id(),
                                                                               app_id=get_app_id())
        rank_data = ranking.get_range(rank_key, start=start - 1, end=end - 1)

        return {r[0]: index + 1 for index, r in enumerate(rank_data)}

    def set_record_has_award(self, rid_list):
        """设置记录为已领取"""
        RankingAwardStatusRepository.update_many_score_has_award(rid_list)

    def init_rank_record_dict(self):
        """初始化榜单上的领取记录 - 字典"""
        from pyshare.const.enums.alliance import AuthLv

        rank_dict = self.get_rank_data()
        alliance_id_list = rank_dict.keys()

        # 获取最近的一场盟战
        last_activity = AllianceBattleActivityRepository.filter_order_by_starttime(limit=1, reverse=True)

        check_time = last_activity[0].clearing_time if last_activity else getCT()
        # 联盟成员列表 （加入时间小于最后一场的结算时间）
        alliance_member_list = AllianceMemberRepository.filter_by_allianceid_list_check_jointime(
            alliance_id_list, check_time, 'RoleGuid', 'AuthLv', 'AllianceId')

        member_dict = {m.role_guid: m for m in alliance_member_list}
        role_id_list = member_dict.keys()

        record_list = RankingAwardStatusRepository.filter_by_rid_list(role_id_list)
        record_dict = {r.role_guid: r for r in record_list}
        record_rid_list = record_dict.keys()

        # 找出没有记录的角色批量create
        need_create_rid = set(role_id_list).difference(set(record_rid_list))

        if need_create_rid:
            # 创建领取记录
            now_time = getCT()
            RankingAwardStatusRepository.create_many([{"RoleGuid": rid, "CreateTime": now_time}
                                                      for rid in need_create_rid])
            record_list = RankingAwardStatusRepository.filter_by_rid_list(role_id_list)
        for record in record_list:
            if has_pass_time(record.create_time, days=get_config_env_set('AllianceBattleRankAwardUpdateCD')):
                record.is_score_award = 0
            if record.is_score_award == 1:
                continue
            member = member_dict.get(record.role_guid)
            rank = rank_dict.get(member.alliance_id)
            if member.auth_lv == AuthLv.Leader:
                leader_sign = AllianceBattleLeaderAwardSignRepository.get_by_allianceid(member.alliance_id)
                if not leader_sign or leader_sign.is_leader_award == 0:
                    self.role_id_list.append(record.role_guid)
                    self.role_rank_dict[rank].append(record)
                else:
                    self.alliance_p_id_list.append(record.role_guid)
                    self.alliance_p_role_rank_dict[rank].append(record)
            else:
                self.alliance_p_id_list.append(record.role_guid)
                self.alliance_p_role_rank_dict[rank].append(record)


class AllianceKillNumSendAward(RankActivitySendAward):
    """
    联盟击杀榜单邮件发奖
    """

    def __init__(self):
        super(AllianceKillNumSendAward, self).__init__(None)
        self.award_type = AllianceSingleAwardType.KillNum
        self.record_filed = 'is_kill_num_award'

    def get_activity(self):
        return None

    def get_activity_name(self):
        return getattr(GameConfigEnvLang(), 'AllianceBattleKillNumMailName')

    def get_start_end(self):
        """
        返回发奖排名区间 Start, End
        :return:
        """
        from app.area.component.alliance_battle.alliance_battle_result_component import AllianceBattleResultComponent
        cfg = AllianceBattleResultComponent.get_single_rank_award_cfg_list(None, self.award_type)
        return cfg[0]['RankMin'], cfg[-1]['RankMax']

    def get_rank_award_cfg(self, rank, is_award_list=True):
        """
        返回排名对应的奖励配置
        :param rank: 排名
        :param is_award_list:
        True则从Activity.AwardList中获取
        否则从Activity.AlliancePAwardList中获取
        :return:
        """
        from app.area.component.alliance_battle.alliance_battle_result_component import AllianceBattleResultComponent
        award_cfg = AllianceBattleResultComponent.get_single_rank_award_cfg(None, self.award_type, rank)

        award_index = award_cfg['Id']

        if award_index not in self.award_id_dict:
            self.award_id_dict[award_index] = create_idx()

        return award_cfg['Award'], award_index, self.award_id_dict[award_index]

    def get_rank_data(self):
        """
        返回 排名start至排名end之间的角色排名字典  {alliance_id: 排名}
        :return:
        """
        from pyshare.bll.utils.area.rank_utils import JoinRankManger
        start, end = self.get_start_end()
        ranking = JoinRankManger()
        rank_key = AllianceBattleRankingKey.NewAllianceBattleKillNumRankingKey.format(srv_id=get_server_id(),
                                                                                      app_id=get_app_id())
        rank_data = ranking.get_range(rank_key, start=start - 1, end=end - 1)
        return {r[0]: index + 1 for index, r in enumerate(rank_data)}

    def set_record_has_award(self, rid_list):
        """设置记录为已领取"""
        RankingAwardStatusRepository.update_many_kill_has_award(rid_list)

    def init_rank_record_dict(self):
        """初始化榜单上的领取记录 - 字典"""
        rank_dict = self.get_rank_data()
        rid_list = rank_dict.keys()

        record_list = RankingAwardStatusRepository.filter_by_rid_list(rid_list)
        record_dict = {r.role_guid: r for r in record_list}
        record_rid_list = record_dict.keys()
        # 找出没有记录的角色批量create
        need_create_rid = set(rid_list).difference(set(record_rid_list))
        if need_create_rid:
            # 创建领取记录
            now_time = getCT()
            RankingAwardStatusRepository.create_many([{"RoleGuid": rid, "CreateTime": now_time}
                                                      for rid in need_create_rid])
            record_list = RankingAwardStatusRepository.filter_by_rid_list(rid_list)

        for record in record_list:
            if has_pass_time(record.create_time, days=get_config_env_set('AllianceBattleRankAwardUpdateCD')):
                record.is_kill_num_award = 0
                setattr(record, self.record_filed, 0)
            if getattr(record, self.record_filed) == 1:
                continue

            rank = rank_dict.get(record.role_guid)
            self.role_id_list.append(record.role_guid)
            self.role_rank_dict[rank].append(record)


class AllianceSiegeSendAward(AllianceKillNumSendAward):
    """
    联盟攻城战榜单邮件发奖
    """

    def __init__(self):
        super(AllianceSiegeSendAward, self).__init__()
        self.award_type = AllianceSingleAwardType.Siege
        self.record_filed = 'is_siege_award'

    def get_activity_name(self):
        return getattr(GameConfigEnvLang(), 'SiegeMailName')

    def set_record_has_award(self, rid_list):
        """设置记录为已领取"""
        RankingAwardStatusRepository.update_many_siege_has_award(rid_list)

    def get_rank_data(self):
        """
        返回 排名start至排名end之间的角色排名字典  {alliance_id: 排名}
        :return:
        """
        from pyshare.bll.utils.area.rank_utils import get_rank_manager
        start, end = self.get_start_end()
        # 获取排名
        rank_key = AllianceSiegeRank.format(srv_id=get_server_id(), app_id=get_app_id())
        rank_data = get_rank_manager().get_range(rank_key, start=start - 1, end=end - 1)
        return {r[0]: index + 1 for index, r in enumerate(rank_data)}


class CommonActivitySendAward(object):
    Personal = 'personal'
    AllianceLeader = 'alliance_leader'
    AllianceMember = 'alliance_member'

    def __init__(self, activity_id, activity_adapter, personal_adapter=None, alliance_adapter=None):
        self.activity_id = activity_id
        self.activity_adapter = activity_adapter
        self.personal_adapter = personal_adapter
        self.alliance_adapter = alliance_adapter

        # 邮件奖励Id字典 /联盟活动表示盟主邮件奖励字典(用于保存相同奖励的邮件奖励id，减少重复创建)
        self.award_id_dict = {}
        self.activity = self.get_activity()  # 活动实例

        self.send_type = self.Personal
        self.subject = getattr(GameConfigEnvLang(), 'ActivityMailSubject')
        self.personal_content = getattr(GameConfigEnvLang(), 'RankActivityContent')
        self.alliance_content = getattr(GameConfigEnvLang(), 'AllianceRankActivityContent')

        self.role_id_list = []  # 待发邮件的rid列表
        self.role_rank_dict = defaultdict(list)  # 数据字段{排名: record_list]}

        self.a_leader_rid_list = []  # 盟友rid列表
        self.a_leader_rank_dict = defaultdict(list)
        self.a_member_rid_list = []  # 盟友rid列表
        self.a_member_rank_dict = defaultdict(list)
        self.a_member_award_id_dict = {}  # 盟友奖励id字段(用于保存相同奖励的邮件奖励id，减少重复创建)

        self.fail_sid_list = []  # 邮件失败rid列表

    @staticmethod
    def get_role_service_id(role_id_list):
        """
        返回 role_id_list中 对应角色的 service_id
        :param role_id_list: role id 列表
        :return: {rid : sid, ...}
        """
        return {r.role_guid: r.service_id for r in
                RoleRepository.filter_by_rid_list(role_id_list,
                                                  'RoleGuid', 'ServiceId')}

    # ====================
    # 根据具体活动重写以下方法
    # ====================
    def get_activity(self):
        """获取活动适配器实例"""
        return self.activity_adapter.objects.get(ActivityId=self.activity_id)

    def get_activity_name(self):
        """获取活动名称"""
        return self.activity.activity_name

    def get_subject(self):
        name_lang = self.get_activity_name()

        subject = {}
        for code, msg in self.subject.items():
            subject[code] = msg.format(name=name_lang[code])

        return subject

    def get_content(self, rank):
        """返回邮件内容"""
        name_lang = self.get_activity_name()

        if self.send_type == self.Personal:
            content = {}
            for code, msg in self.personal_content.items():
                content[code] = msg.format(name=name_lang[code], rank=rank)

        else:
            content = {}
            for code, msg in self.alliance_content.items():
                content[code] = msg.format(name=name_lang[code], rank=rank)

        return content

    def get_award_list_cfg(self):
        """获取活动奖励配置"""
        if self.send_type == self.Personal:
            return self.activity.personal_award_list
        elif self.send_type == self.AllianceLeader:
            return self.activity.alliance_leader_award_list
        else:
            return self.activity.alliance_member_award_list

    def get_activity_range_cfg(self):
        """获取排名奖励区间配置"""
        if self.send_type == self.Personal:
            return self.activity.personal_range_list
        else:
            return self.activity.alliance_range_list

    def get_start_end(self):
        """返回发奖排名区间 Start, End"""
        range_cfg = self.get_activity_range_cfg()
        return range_cfg[0][0] - 1, range_cfg[-1][-1] - 1

    def rank_to_award_index(self, rank):
        """返回排名对应的奖励下标"""
        for w_index, r in enumerate(self.get_activity_range_cfg()):
            if r[0] <= rank <= r[1]:
                return w_index
        return None

    def get_rank_award_cfg(self, rank, is_award_list=True):
        """
        返回排名对应的奖励配置
        :param rank: 排名
        :param is_award_list:
        True则从Activity.AwardList中获取
        否则从Activity.AlliancePAwardList中获取
        :return:
        """
        award_index = self.rank_to_award_index(rank)
        if award_index not in self.award_id_dict:
            self.award_id_dict[award_index] = create_idx()

        return self.get_award_list_cfg()[award_index], award_index, self.award_id_dict[award_index]

    def set_record_has_award(self, rid_list):
        if self.send_type == self.Personal:
            self.personal_adapter.objects. \
                filter(RoleGuid__in=rid_list, ActivityId=self.activity_id). \
                update(HasAward=1)
        else:
            self.alliance_adapter.objects. \
                filter(RoleGuid__in=rid_list, ActivityId=self.activity_id). \
                update(HasAward=1)

    def response_callback(self, res, s_id_to_role_id_dict):
        """
        回调结果处理
        发送成功的邮件，将角色领奖记录置成1
        发送失败的邮件，将role_id 计入 fail_sid_list
        :param res:
        :param s_id_to_role_id_dict: {sid: rid}
        :return:
        """
        if res['Success']:
            rid_list = [s_id_to_role_id_dict.get(sid) for sid in res['Success']]
            self.set_record_has_award(rid_list)
        self.fail_sid_list += list(set(s_id_to_role_id_dict.keys()) - set(res['Success']))

    def get_not_award_record_list(self, id_list):
        if self.send_type == self.Personal:
            return self.personal_adapter.objects.filter(ActivityId=self.activity_id, RoleGuid__in=id_list,
                                                        HasAward=0)
        else:
            return self.alliance_adapter.objects.filter(ActivityId=self.activity_id, AllianceId__in=id_list,
                                                        HasAward=0)

    # TODO: 必重写
    def get_rank_data(self):
        """
        返回 排名start至排名end之间的角色排名字典  {role_id/alliance_id: 排名}
        :return:
        """
        start, end = self.get_start_end()
        return {}
        # return ReusableActivitySendAward.reusable_rank_data(self.activity_id, ReusableActivityRankType.Alliance,
        #                                                     start, end)

    def init_rank_record_dict(self):
        """
        初始化 榜单上待发奖的角色数据
        role_id_list 需要发奖的角色id列表
        role_rank_dict 发奖方法中的发奖数据 {排名: [role_id,]}
        :return:
        """
        rank_dict = self.get_rank_data()
        id_list = rank_dict.keys()
        record_list = self.get_not_award_record_list(id_list)

        if self.send_type == self.Personal:
            self.role_id_list = id_list
            self.role_rank_dict = {rank_dict.get(r.role_guid): [r] for r in record_list}
        else:
            for record in record_list:
                rank = rank_dict.get(record.alliance_id)
                if record.is_leader:
                    self.a_leader_rid_list.append(record.role_guid)
                    self.a_leader_rank_dict[rank].append(record)
                else:
                    self.a_member_rid_list.append(record.role_guid)
                    self.a_member_rank_dict[rank].append(record)

    def send_mail_award_of_activity(self, service_id_dict, rank_dict, is_award_list=True):
        """
        发送奖励
        个人排行奖励
        :return:
        """
        from app.admin.core.admin_component_center import AdminComponentCenter
        admin_cc = AdminComponentCenter()

        for rank, record_list in rank_dict.iteritems():
            # 邮件奖励说明
            content = self.get_content(rank)
            subject = self.get_subject()

            award_list, index, award_id = self.get_rank_award_cfg(rank, is_award_list)
            s_id_to_role_id_dict = {service_id_dict.get(r.role_guid): r.role_guid for r in record_list}
            res_data = admin_cc.activity_admin.send_mail(award_list, s_id_to_role_id_dict.keys(), subject,
                                                         content)
            self.response_callback(res_data, s_id_to_role_id_dict)

    def send_personal_award(self):
        """发送个人排行奖励"""
        self.init_rank_record_dict()
        service_id_dict = self.get_role_service_id(self.role_id_list)
        self.send_mail_award_of_activity(service_id_dict, self.role_rank_dict)

    def send_alliance_award(self):
        """发送联盟排行奖励"""
        self.init_rank_record_dict()
        # 发送盟主奖励
        self.send_type = self.AllianceLeader
        leader_sid_list = self.get_role_service_id(self.a_leader_rid_list)
        self.send_mail_award_of_activity(leader_sid_list, self.a_leader_rank_dict)

        # 发送盟员奖励
        self.send_type = self.AllianceMember
        member_sid_list = self.get_role_service_id(self.a_member_rid_list)
        self.send_mail_award_of_activity(member_sid_list, self.a_member_rank_dict, is_award_list=False)

    def send_award(self):
        """
        执行发奖
        外部只需要调用该方法就可完成发奖
        :return:
        """
        # 发送个人排行奖励
        if self.personal_adapter:
            self.send_type = self.Personal
            self.send_personal_award()

        # 发送联盟排行奖励
        if self.alliance_adapter:
            self.send_type = self.AllianceLeader
            self.send_alliance_award()

        return self.fail_sid_list


class RuinsActivitySendAward(CommonActivitySendAward):
    def __init__(self, activity_id):
        super(RuinsActivitySendAward, self).__init__(
            activity_id, RuinsActivityRepository.adapter_class,
            personal_adapter=RuinsRoleRepository.adapter_class,
            alliance_adapter=cadts.RankAllianceMemberRecordAdapter
        )

    def get_activity_name(self):
        """获取活动名称"""
        env_key = getProfile('TcActivityType', Class=ActivityClass.Ruins, Type=0).LangEnvKey
        return getattr(GameConfigEnvLang(), env_key)

    def get_not_award_record_list(self, id_list):
        if self.send_type == self.Personal:
            return self.personal_adapter.objects.filter(RuinsId=self.activity_id, RoleGuid__in=id_list,
                                                        HasAward=0)
        else:
            return self.alliance_adapter.objects.filter(ActivityId=self.activity_id, AllianceId__in=id_list,
                                                        HasAward=0)

    def get_rank_data(self):
        """
        返回 排名start至排名end之间的角色排名字典  {role_id/alliance_id: 排名}
        :return:
        """
        from app.area.component.ruins_component import RuinsRankUtils
        if self.send_type == self.Personal:
            rank_redis_key = RuinsRankUtils.create_ruins_activity_rank_key(self.activity_id, RuinsRankType.RankPerson)
        else:
            rank_redis_key = RuinsRankUtils.create_ruins_activity_rank_key(self.activity_id, RuinsRankType.RankAlliance)

        start, end = self.get_start_end()
        from app.area.core.component_center import ComponentCenter
        area_cc = ComponentCenter()
        rank_data = area_cc.leaderboard.get_rank_list(rank_redis_key, start=start, end=end, need_id=True)
        return {r[0]: index + 1 for index, r in enumerate(rank_data)}

    def set_record_has_award(self, rid_list):
        if self.send_type == self.Personal:
            self.personal_adapter.objects. \
                filter(RoleGuid__in=rid_list, RuinsId=self.activity_id). \
                update(HasAward=1)
        else:
            self.alliance_adapter.objects. \
                filter(RoleGuid__in=rid_list, ActivityId=self.activity_id). \
                update(HasAward=1)


class QueenJewelryHistoryRankAward(RankActivitySendAward):
    """
    如意赠佳人历史最高积分榜单
    """

    def __init__(self, activity_id):
        super(QueenJewelryHistoryRankAward, self).__init__(activity_id)
        self.content = getattr(GameConfigEnvLang(), 'QueenJewelryHistoryRankContent')

    def get_activity(self):
        """获取活动"""
        return QueenJewelryActivityRepository.get_by_activityid(self.activity_id)

    def get_activity_range_cfg(self):
        """获取排名奖励区间配置"""
        return self.activity.range

    def get_activity_name(self):
        """获取活动名称"""
        env_key = getProfile('TcActivityType', Class=ActivityClass.QueenJewelry,
                                Type=ActivityType.QueenJewelry).LangEnvKey
        return getattr(GameConfigEnvLang(), env_key)

    def get_award_list_cfg(self):
        """获取活动奖励配置"""
        return self.activity.award_list

    def get_rank_data(self):
        """
        返回 排名start至排名end之间的角色排名字典  {role_id: 排名}
        :return:
        """
        from app.area.component.queen_jewelry.queen_jewelry_component import QueenJewelryActivityFacade
        from pyshare.const.enums.queen_jewelry import QueenJewelryRankType
        from app.area.core.component_center import ComponentCenter

        area_cc = ComponentCenter()
        rank_redis_key = QueenJewelryActivityFacade.get_rank_key_by_type(self.activity_id,
                                                                         QueenJewelryRankType.HistoryMaxScore)
        start, end = self.get_start_end()
        rank_data = area_cc.leaderboard.get_rank_list(rank_redis_key, start=start, end=end, need_id=True)
        return {r[0]: index + 1 for index, r in enumerate(rank_data)}

    def get_not_award_record_list(self, *args):
        return QueenJewelryRoleRecordRepository.filter_by_history_not_award(self.role_id_list, self.activity_id)

    def set_record_has_award(self, rid_list):
        QueenJewelryRoleRecordRepository.update_many_history_has_award(rid_list, self.activity_id)


class QueenJewelryActiveRankAward(RankActivitySendAward):
    """
    如意赠佳人累积活跃积分榜单
    """

    def __init__(self, activity_id):
        super(QueenJewelryActiveRankAward, self).__init__(activity_id)
        self.content = getattr(GameConfigEnvLang(), 'QueenJewelryActiveRankContent')

    def get_activity(self):
        """获取活动"""
        return QueenJewelryActivityRepository.get_by_activityid(self.activity_id)

    def get_activity_range_cfg(self):
        """获取排名奖励区间配置"""
        return self.activity.active_range

    def get_activity_name(self):
        """获取活动名称"""
        env_key = getProfile('TcActivityType', Class=ActivityClass.QueenJewelry,
                                Type=ActivityType.QueenJewelry).LangEnvKey
        return getattr(GameConfigEnvLang(), env_key)

    def get_award_list_cfg(self):
        """获取活动奖励配置"""
        return self.activity.active_award_list

    def get_rank_data(self):
        """
        返回 排名start至排名end之间的角色排名字典  {role_id: 排名}
        :return:
        """
        from app.area.component.queen_jewelry.queen_jewelry_component import QueenJewelryActivityFacade
        from pyshare.const.enums.queen_jewelry import QueenJewelryRankType
        from app.area.core.component_center import ComponentCenter

        area_cc = ComponentCenter()
        rank_redis_key = QueenJewelryActivityFacade.get_rank_key_by_type(self.activity_id,
                                                                         QueenJewelryRankType.ActiveScore)
        start, end = self.get_start_end()
        rank_data = area_cc.leaderboard.get_rank_list(rank_redis_key, start=start, end=end, need_id=True)
        return {r[0]: index + 1 for index, r in enumerate(rank_data)}

    def get_not_award_record_list(self, *args):
        return QueenJewelryRoleRecordRepository.filter_by_active_not_award(self.role_id_list, self.activity_id)

    def set_record_has_award(self, rid_list):
        QueenJewelryRoleRecordRepository.update_many_active_has_award(rid_list, self.activity_id)


class BanquetHistoryRankAward(RankActivitySendAward):
    """
    满汉全席历史最高积分榜单
    """

    def __init__(self, activity_id):
        super(BanquetHistoryRankAward, self).__init__(activity_id)
        self.content = getattr(GameConfigEnvLang(), 'BanquetHistoryRankContent')

    def get_activity(self):
        """获取活动"""
        return BanquetActivityRepository.get_by_activityid(self.activity_id)

    def get_activity_range_cfg(self):
        """获取排名奖励区间配置"""
        return self.activity.history_range_list

    def get_activity_name(self):
        """获取活动名称"""
        env_key = getProfile('TcActivityType', Class=ActivityClass.Banquet, Type=ActivityType.Banquet).LangEnvKey
        return getattr(GameConfigEnvLang(), env_key)

    def get_award_list_cfg(self):
        """获取活动奖励配置"""
        return self.activity.history_award_list

    def get_rank_data(self):
        """
        返回 排名start至排名end之间的角色排名字典  {role_id: 排名}
        :return:
        """
        from app.area.component.banquet_component import BanquetComponent
        from pyshare.const.enums.banquet import BanquetRankType
        from app.area.core.component_center import ComponentCenter

        area_cc = ComponentCenter()
        rank_redis_key = BanquetComponent.get_rank_key_by_type(self.activity_id,
                                                               BanquetRankType.HistoryMaxScore)
        start, end = self.get_start_end()
        rank_data = area_cc.leaderboard.get_rank_list(rank_redis_key, start=start, end=end, need_id=True)
        return {r[0]: index + 1 for index, r in enumerate(rank_data)}

    def get_not_award_record_list(self, *args):
        return BanquetRoleRecordRepository.filter_by_history_not_award(self.role_id_list, self.activity_id)

    def set_record_has_award(self, rid_list):
        BanquetRoleRecordRepository.update_many_history_has_award(rid_list, self.activity_id)


class BanquetActiveRankAward(RankActivitySendAward):
    """
    满汉全席累积活跃积分榜单
    """

    def __init__(self, activity_id):
        super(BanquetActiveRankAward, self).__init__(activity_id)
        self.content = getattr(GameConfigEnvLang(), 'BanquetActiveRankContent')

    def get_activity(self):
        """获取活动"""
        return BanquetActivityRepository.get_by_activityid(self.activity_id)

    def get_activity_range_cfg(self):
        """获取排名奖励区间配置"""
        return self.activity.active_range_list

    def get_activity_name(self):
        """获取活动名称"""
        env_key = getProfile('TcActivityType', Class=ActivityClass.Banquet, Type=ActivityType.Banquet).LangEnvKey
        return getattr(GameConfigEnvLang(), env_key)

    def get_award_list_cfg(self):
        """获取活动奖励配置"""
        return self.activity.active_award_list

    def get_rank_data(self):
        """
        返回 排名start至排名end之间的角色排名字典  {role_id: 排名}
        :return:
        """
        from app.area.component.banquet_component import BanquetComponent
        from pyshare.const.enums.banquet import BanquetRankType
        from app.area.core.component_center import ComponentCenter

        area_cc = ComponentCenter()
        rank_redis_key = BanquetComponent.get_rank_key_by_type(self.activity_id,
                                                               BanquetRankType.ActiveScore)
        start, end = self.get_start_end()
        rank_data = area_cc.leaderboard.get_rank_list(rank_redis_key, start=start, end=end, need_id=True)
        return {r[0]: index + 1 for index, r in enumerate(rank_data)}

    def get_not_award_record_list(self, *args):
        return BanquetRoleRecordRepository.filter_by_active_not_award(self.role_id_list, self.activity_id)

    def set_record_has_award(self, rid_list):
        BanquetRoleRecordRepository.update_many_active_has_award(rid_list, self.activity_id)
